import backtrader as bt
import matplotlib.pyplot as plt
import datetime
import pandas as pd
import backtrader.analyzers as btanalyzers

class Ketele(bt.Indicator):
    params = (
        ('ema', 20),
        ('atr', 17)
    )

    lines = ('expo', 'atr', 'upper', 'lower')
    plotinfo = dict(subplot=False)
    plotlines = dict(
        upper = dict(ls = '--'),
        lower = dict(_samecolor = True)
    )


    def __init__(self):
        self.l.expo = bt.talib.EMA(self.datas[0].close, timeperiod=self.params.ema)
        self.l.atr = bt.talib.ATR(self.data.high,self.data.low, self.data.close, timeperiod=self.params.atr)
        self.l.upper = self.l.expo + self.l.atr
        self.l.lower = self.l.expo - self.l.atr


class KChanelStrategy(bt.Strategy):
    def log(self, txt, dt=None):
        ''' Logging function fot this strategy'''
        dt = dt or self.data.datetime[0]
        if isinstance(dt, float):
            dt = bt.num2date(dt)
        print('%s, %s' % (dt.isoformat(), txt))
    
    def __init__(self):
        self.dataclose = self.datas[0].close
        self.order = None
        self.ketler = Ketele()

    def notify_order(self, order):
        if order.status in [order.Submitted, order.Accepted]:
            return
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log('BUY EXECUTED, %.2f' % order.executed.price)
            elif order.issell():
                self.log('SELL EXECUTED, %.2f' % order.executed.price)
            self.bar_executed = len(self)
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log('Order Canceled/Margin/Rejected')
        self.order = None

    def notify_trade(self, trade):
        if not trade.isclosed:
            return

        self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                 (trade.pnl, trade.pnlcomm))
    
    def next(self):
        if not self.position:
            if self.dataclose[0] > self.ketler.upper[0]:
                self.order = self.order_target_percent(target=0.95)
        else:
            if self.dataclose[0] < self.ketler.expo[0]:
                self.order = self.sell()

if __name__ == "__main__":
    cerebro = bt.Cerebro()
    data = bt.feeds.YahooFinanceData(
        dataname="AAPL",
        fromdate=datetime.datetime(2020,1,1),
        todate=datetime.datetime(2020,12,30),
        timeframe=bt.TimeFrame.Days
    )
    cerebro.adddata(data)
    cerebro.broker.setcash(100000.0)
    cerebro.broker.startingcash

    cerebro.addstrategy(KChanelStrategy)
    cerebro.broker.setcommission(commission=0.0003)

    cerebro.addsizer(bt.sizers.PercentSizer, percents=98)


    cerebro.addanalyzer(btanalyzers.SharpeRatio, _name="sharpe")
    cerebro.addanalyzer(btanalyzers.DrawDown, _name="drawdown")
    cerebro.addanalyzer(btanalyzers.Returns, _name="returns")


    print('the beigin value is {:.2f}'.format(cerebro.broker.getvalue()))

    back = cerebro.run()

    print('the end value is {:.2f}'.format(cerebro.broker.getvalue()))


    par_list = [[x.analyzers.returns.get_analysis()['rtot'],
                 x.analyzers.returns.get_analysis()['rnorm100'],
                 x.analyzers.drawdown.get_analysis()['max']['drawdown'],
                 x.analyzers.sharpe.get_analysis()['sharperatio']
                ]for x in back
    ]
    par_df = pd.DataFrame(par_list, columns=['Total returns', 'APR', 'drawdown', 'sharperatio'])
    print(par_df)

    cerebro.plot(style='candle')

